Tool
R
Python
Author

Tony D

Published

July 10, 2025

github tending project since 2024.

load package

Code
library(httr)
library(jsonlite)
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.2     ✔ tibble    3.3.0
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.0.4     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter()  masks stats::filter()
✖ purrr::flatten() masks jsonlite::flatten()
✖ dplyr::lag()     masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Code
library(ggplot2)
library(lubridate)
library(plotly)

Attaching package: 'plotly'

The following object is masked from 'package:ggplot2':

    last_plot

The following object is masked from 'package:httr':

    config

The following object is masked from 'package:stats':

    filter

The following object is masked from 'package:graphics':

    layout
Code
library(scales)

Attaching package: 'scales'

The following object is masked from 'package:purrr':

    discard

The following object is masked from 'package:readr':

    col_factor

get data

Code
# Install if needed
# install.packages(c("httr", "jsonlite"))

# Calculate the date one week ago
#since <- format(Sys.Date() - 30, "%Y-%m-%d")

since <- "2024-01-01"

# Query GitHub search API for repos created in the last week, ordered by stars
res <- GET(
  url = "https://api.github.com/search/repositories",
  query = list(
    q = paste0("created:>", since),
    sort = "stars",
    order = "desc",
    per_page = 20
  ),
  add_headers(Accept = "application/vnd.github.v3+json")
)

stop_for_status(res)
data <- content(res, as = "parsed", simplifyVector = TRUE)

# Extract details
top <- data$items
df <- data.frame(
  name        = top$full_name,
  stars       = top$stargazers_count,
  forks       = top$forks_count,
  watchers    = top$watchers_count,
  created_at  = top$created_at,
  summary     = top$description,
  url         = top$html_url,
  stringsAsFactors = FALSE
)

glimpse(df)
Rows: 20
Columns: 7
$ name       <chr> "deepseek-ai/DeepSeek-V3", "deepseek-ai/DeepSeek-R1", "Digi…
$ stars      <int> 98160, 90473, 65966, 65775, 65124, 60190, 60125, 58762, 570…
$ forks      <int> 15978, 11678, 1251, 19126, 7440, 7044, 3160, 6793, 5162, 83…
$ watchers   <int> 98160, 90473, 65966, 65775, 65124, 60190, 60125, 58762, 570…
$ created_at <chr> "2024-12-26T09:52:40Z", "2025-01-20T11:57:28Z", "2024-05-30…
$ summary    <chr> NA, NA, "DigitalPlat FreeDomain: Free Domain For Everyone",…
$ url        <chr> "https://github.com/deepseek-ai/DeepSeek-V3", "https://gith…

clean data

Code
df$name_label <- paste0(df$name, "
", format(as.Date(df$created_at), "%Y-%m-%d"))

# Reshape data to long format for plotting
df_long <- df %>%
  select(name,name_label, url, stars, forks, watchers) %>%
  pivot_longer(cols = c("stars", "forks", "watchers"),
               names_to = "metric", values_to = "count") |> mutate(text =paste0("<a href='",url,"' target='_blank'>",name_label)
               ) |> mutate(text = factor(text, levels = rev(unique(text[order(-count)]))))
     
glimpse(df_long)
Rows: 60
Columns: 6
$ name       <chr> "deepseek-ai/DeepSeek-V3", "deepseek-ai/DeepSeek-V3", "deep…
$ name_label <chr> "deepseek-ai/DeepSeek-V3\n2024-12-26", "deepseek-ai/DeepSee…
$ url        <chr> "https://github.com/deepseek-ai/DeepSeek-V3", "https://gith…
$ metric     <chr> "stars", "forks", "watchers", "stars", "forks", "watchers",…
$ count      <int> 98160, 15978, 98160, 90473, 11678, 90473, 65966, 1251, 6596…
$ text       <fct> <a href='https://github.com/deepseek-ai/DeepSeek-V3' target…

ggplot

Code
# Bar chart
gg <- ggplot(df_long, aes(x = reorder(name_label, count), y = count, fill = metric, customdata = url)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(label = scales::label_number(accuracy = 0.1, scale_cut = scales::cut_short_scale())(count)), position = position_dodge(width = 0.9), hjust = -0.1, size = 3) +
  labs(
    title = "Top 20 Fastest Growing GitHub Projects (since 2024)",
    x = "Repository",
    y = "Count",
    fill = "Metric"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  coord_flip()

gg

plotly

Code
fig <- plot_ly(
  data = df_long,
  x = ~count,
  y = ~text,
  color = ~metric,
  type = 'bar',
  orientation = 'h',
  customdata = ~url,
  texttemplate = '%{x:.2s}',
  textposition = 'outside',
  hovertemplate = paste(
    "<b>Repository:</b> %{y}<br>",
    "<b>Count:</b> %{x:.2s}<br>",
    "<b>Metric:</b> %{fullData.name}<br>",
    "<b>URL:</b> %{customdata}<extra></extra>"
  )

) %>%
  layout(
    title = "Top 20 Fastest Growing GitHub Projects (since 2024)",
    xaxis = list(title = "Count", range = c(0, max(df_long$count) * 1.15)),
    yaxis = list(title = "Repository", categoryorder = "array", categoryarray = levels(df_long$text)),
    barmode = "group",
    legend = list(title = list(text = "Metric")),
    margin = list(b = 120)
   ,height=900
  )
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
Code
fig